package com.base.cn.platform.os.common.mybatis;

import com.base.cn.platform.os.common.constants.CacheConstants;
import com.base.cn.platform.os.common.redis.RedisChannel;
import com.base.cn.platform.os.common.utils.DateUtils;
import com.base.cn.platform.os.common.utils.ReflectionUtils;
import net.oschina.j2cache.cache.support.util.SpringUtil;
import org.apache.ibatis.jdbc.SQL;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 添加数据SQL提供类
 */
public class BaseInsertProvider<E> extends BaseProvider{
    /***
     * 获取批量添加的SQL方法
     * @param map
     * @return 返回可执行的SQL
     */
    public String batchSaveTableName(Map<String,Object> map) throws IllegalAccessException{
        List<E> entityList = (List<E>) map.get("list");
        if( !ObjectUtils.isEmpty(entityList)){
            RedisChannel redisChannel = SpringUtil.getBean(RedisChannel.class);
            entityList.stream().filter(e->!ObjectUtils.isEmpty(e)).forEachOrdered(entity ->{
                BigDecimal id =(BigDecimal) ReflectionUtils.getFieldValue(entity, "id");
                if(ObjectUtils.isEmpty(id)||id.compareTo( new BigDecimal(0))==0){
                    ReflectionUtils.invokeMethod(entity,"setId",BigDecimal.class,new BigDecimal(redisChannel.getNextId(CacheConstants.ID,1L)));
                }
            });
            Map<String,Object> result = MyBatisUtils.getEntityAllField(entityList);
            if(ObjectUtils.isEmpty(result)){
                return null;
            }
            String tableName =(String) map.get("tableName");
            if(tableName !=null && !tableName.trim().equals("")){
                Field[] _fields = (Field[])result.get("fields");
                return getBatchSaveSql(entityList,_fields,tableName);
            }
        }
        return null;
    }
    /***
     * 获取批量添加的SQL方法
     * @param map
     * @return 返回可执行的SQL
     */
    public String batchSave(Map<String,Object> map) throws IllegalAccessException{
        List<E> entityList = (List<E>) map.get("list");
        if( !ObjectUtils.isEmpty(entityList)){
            RedisChannel redisChannel = SpringUtil.getBean(RedisChannel.class);
            entityList.stream().filter(e->!ObjectUtils.isEmpty(e)).forEachOrdered(entity ->{
                BigDecimal id =(BigDecimal) ReflectionUtils.getFieldValue(entity, "id");
                if(ObjectUtils.isEmpty(id)||id.compareTo( new BigDecimal(0))==0){
                    ReflectionUtils.invokeMethod(entity,"setId",BigDecimal.class,new BigDecimal(redisChannel.getNextId(CacheConstants.ID,1L)));
                }
            });
            Map<String,Object> result = MyBatisUtils.getEntityAllField(entityList);
            if(ObjectUtils.isEmpty(result)){
                return null;
            }
            E entity = (E)result.get("entity");
            String tableName = MyBatisUtils.getTableName(entity);
            Field[] _fields = (Field[])result.get("fields");
            return getBatchSaveSql(entityList,_fields,tableName);
        }
        return null;
    }

    /**
     * 获取添加的SQL方法(带有表名的)
     * @param map
     * @return 返回可执行SQL语句
     * @throws Exception
     */
    public String saveTableName(Map<String,Object> map) throws IllegalAccessException {
        E entity = (E)map.get("entity");
        if(entity!=null){
            //设置主键ID
            BigDecimal id =(BigDecimal) ReflectionUtils.getFieldValue(entity, "id");
            if(ObjectUtils.isEmpty(id)||id.compareTo( new BigDecimal(0))==0){
                RedisChannel redisChannel = SpringUtil.getBean(RedisChannel.class);
                ReflectionUtils.invokeMethod(entity,"setId",BigDecimal.class,new BigDecimal(redisChannel.getNextId(CacheConstants.ID,1L)));
            }
            String tableName = (String)map.get("tableName");
            if(tableName !=null && !tableName.trim().equals("")){
                Field[] fields = MyBatisUtils.getEntityAllField(entity);
                return this.getSaveSql(entity,tableName,fields);
            }

        }
        return null;
    }

    /**
     * 获取添加的SQL方法
     * @param map
     * @return 返回可执行SQL语句
     * @throws Exception
     */
    public String save(Map<String,Object> map) throws IllegalAccessException, NoSuchFieldException, InvocationTargetException {
        E entity = (E)map.get("entity");
        if(!ObjectUtils.isEmpty(entity)){
            //设置主键ID
            BigDecimal id =(BigDecimal) ReflectionUtils.getFieldValue(entity, "id");
            if(ObjectUtils.isEmpty(id)||id.compareTo( new BigDecimal(0))==0){
                RedisChannel redisChannel = SpringUtil.getBean(RedisChannel.class);
                ReflectionUtils.invokeMethod(entity,"setId",BigDecimal.class,new BigDecimal(redisChannel.getNextId(CacheConstants.ID,1L)));
            }
            String tableName = MyBatisUtils.getTableName(entity);;
            Field[] fields = MyBatisUtils.getEntityAllField(entity);
            return this.getSaveSql(entity,tableName,fields);
        }
        return null;
    }


    /**
     * 获取批量添加SQL
     * @param entityList
     * @param fields
     * @param tableName
     * @return
     */
    private String getBatchSaveSql(List<E> entityList ,Field[] fields,String tableName) throws IllegalAccessException{
        String columnNames = "";
        for(Field field : fields){
            String name = field.getName();
            //添加语句 排除id 参数，mybatis 拦截器统一处理
            if (!name.toLowerCase().equals("createtime") && !name.toLowerCase().equals("updatetime")) {
                columnNames += "`" + name + "`,";
            }
        }
        if(columnNames.endsWith(",")){
            columnNames =columnNames.substring(0,columnNames.length()-1);
        }
        columnNames +=",`createTime`,`updateTime`";
        StringBuilder stringBuilder = new StringBuilder("INSERT INTO "+"`"+tableName+"`("+columnNames+") VALUES");
        Map<String,Object> map = new HashMap<>(2);
        for(int i=0;i<entityList.size();i++){
            String _values = "(";
            for(Field field : fields){
                String name = field.getName();
                if(!name.toLowerCase().equals("createtime") && !name.toLowerCase().equals("updatetime")){
                    _values+="#{list["+i+"]."+field.getName()+"},";
                }
                if(name.toLowerCase().equals("createtime")){
                    map = handerTime(field,entityList.get(i),map);
                }
                if(name.toLowerCase().equals("updatetime")){
                    map = handerTime(field,entityList.get(i),map);
                }
            }
            _values = getValues(map, _values);
            //去掉最后一个“,”号
            if(_values.endsWith(",")){
                _values = _values.substring(0,_values.length()-1);
            }
            _values+=")";
            stringBuilder.append(_values);
            //如果不是最后一条记录则添加逗号隔开
            if(i<entityList.size()-1){
                stringBuilder.append(",");
            }
        }
        String sql = stringBuilder.toString();
        if(sql.trim().endsWith(",")){
            sql = sql.trim().substring(0,sql.trim().length()-1);
        }
        return sql;
    }

    private String getValues(Map<String, Object> map, String _values) {
        String time =  DateUtils.format(new Date(),"yyyy-MM-dd HH:mm:ss");
        if(map.containsKey("createtime")){
            _values+="'"+map.get("createtime")+"',";
        }else{
            _values+="'"+time+"',";
        }
        if(map.containsKey("updatetime")){
            _values+="'"+map.get("updatetime")+"'";
        }else{
            _values+="'"+time+"'";
        }
        return _values;
    }


    private Map<String,Object> handerTime(Field field,E entity,Map<String,Object> map) throws IllegalAccessException {
        String time =  DateUtils.format(new Date(),"yyyy-MM-dd HH:mm:ss");
        Object value = field.get(entity);
        if(ObjectUtils.isEmpty(value)){
            map.put(field.getName().toLowerCase(),time);
        }else{
            String tempUpdateTime = DateUtils.format((Date) value,"yyyy-MM-dd HH:mm:ss");
            map.put(field.getName().toLowerCase(),tempUpdateTime);
        }
        return map;
    }

    private String getSaveSql(E entity,String tableName,Field[] fields) throws IllegalAccessException{
        if(!ObjectUtils.isEmpty(fields)){
            String time = DateUtils.format(new Date(),"yyyy-MM-dd HH:mm:ss");
            SQL sql = new SQL();
            sql.INSERT_INTO("`"+tableName+"`");
            String values= " VALUES(";
            for(Field field : fields){
                String name = field.getName();
                Object value = field.get(entity);
                //添加语句 排除id 参数，mybatis 拦截器统一处理
                if(!ObjectUtils.isEmpty(value) && !name.toLowerCase().equals("createtime") && !name.toLowerCase().equals("updatetime")){
                    sql.INTO_COLUMNS("`"+name+"`");
                    values+=("#{entity."+name+"},");
                }else if(name.toLowerCase().equals("createtime") || name.toLowerCase().equals("updatetime")){
                    sql.INTO_COLUMNS("`"+name+"`");
                    if(ObjectUtils.isEmpty(value)){
                        values +=" '"+time+"',";
                    }else{
                        String tempTime = DateUtils.format((Date) value,"yyyy-MM-dd HH:mm:ss");
                        values +=" '"+tempTime+"',";
                    }
                }
            }
            if(!sql.toString().toLowerCase().contains("createtime")){
                sql.INTO_COLUMNS("`createTime`");
                values +=" '"+time+"',";
            }
            if(!sql.toString().toLowerCase().contains("updatetime")){
                sql.INTO_COLUMNS("`updatetime`");
                values +=" '"+time+"',";
            }
            if(values.trim().endsWith(",")){
                values = " "+values.trim().substring(0,values.trim().length()-1);
            }
            values+=")";
            return sql.toString()+values;
        }
        return null;
    }
}
